using System.Collections.Generic;
using System.IO;
using System.Linq;
using System;

using MyUtils;

namespace SolutionOrchestrator
{
	public static class PathHelper
	{
		static readonly Dictionary<string, bool> _cacheFileExists = new Dictionary<string, bool>();

		public static void CacheReset()
		{
			_cacheFileExists.Clear();
		}

		public static bool FileExists(string filePath)
		{
			bool result;
			if(!_cacheFileExists.TryGetValue(filePath, out result))
			{
				_cacheFileExists[filePath] = result = File.Exists(filePath);
			}
			return result;
		}

		public static string GetDirectoryName(string path)
		{
			return GetDirectoryNameSimple(path);
		}

		static string GetDirectoryNameSimple(string path)
		{
			var sep = path.LastIndexOf(Path.DirectorySeparatorChar);
			if (sep < 0)
			{
				throw new Exception("Directory is absent");
			}
			return path.Substring(0, sep);
		}

		public static string BuildRelativeFromTo(string absoluteSourceDir, string absoluteTargetPath, string absoluteCommonDir, bool nullIfFileNotExists = true)
		{
			var path = BuildRelativeFromTo(absoluteSourceDir, absoluteTargetPath);
			if (nullIfFileNotExists && path != null)
			{
				if (!FileExists(Path.Combine(absoluteSourceDir, path)))
				{
					return null;
				}
			}

			// required common dir (solution)
			if (!absoluteTargetPath.StartsWith(absoluteCommonDir, StringComparison.InvariantCultureIgnoreCase))
			{
				return null;
			}

			return path;
		}

		/// <summary>
		/// Generate relative path from absoluteSourceDir to absoluteTargetPath
		/// </summary>
		public static string BuildRelativeFromTo(string absoluteSourceDir, string absoluteTargetPath)
		{
			if (!Path.IsPathRooted(absoluteSourceDir))
			{
				throw new ArgumentException(@"Path should be absolute", "absoluteSourceDir");
			}
			if (!Path.IsPathRooted(absoluteTargetPath))
			{
				throw new ArgumentException(@"Path should be absolute", "absoluteTargetPath");
			}

			// normalize
			absoluteSourceDir = absoluteSourceDir.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar).TrimEnd(Path.DirectorySeparatorChar);
			absoluteTargetPath = absoluteTargetPath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar).TrimEnd(Path.DirectorySeparatorChar);

			var current = absoluteSourceDir;
			var toCommon = "";
			while (!absoluteTargetPath.StartsWith(current, StringComparison.OrdinalIgnoreCase))
			{
				toCommon += "..\\";
				var i = current.LastIndexOf(Path.DirectorySeparatorChar);
				if (i < 0)
				{
					// no way
					return null;
				}
				current = current.Substring(0, i).TrimEnd(Path.DirectorySeparatorChar);
			}

			var fromSln = absoluteTargetPath.Substring(current.Length).TrimStart(Path.DirectorySeparatorChar);
			var goodRef = Path.Combine(toCommon, fromSln);

			return goodRef;
		}
	}
}